home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The CICA Windows Explosion!
/
The CICA Windows Explosion! - Disc 2.iso
/
programr
/
msjv6-5.zip
/
WINDOS.ZIP
/
WINHEAP.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-01
|
11KB
|
408 lines
/*
WINHEAP.C -- Heap routines for Microsoft Windows
_amblksiz
_fmalloc, _fcalloc, _fexpand, _frealloc, _ffree, _fmsize
_nmalloc, _ncalloc, _nexpand, _nrealloc, _nfree, _nmsize
_malloc, _calloc, _expand, _realloc, _free, _msize
from Microsoft Systems Journal, September 1991
Andrew Schulman (andrew@pharlap.com)
*/
#include <windows.h>
#include <memory.h>
#include <stdlib.h>
#ifdef __BORLANDC__
#include "based.h"
#else
#include <malloc.h>
#endif
#include "winio.h"
#ifdef __BORLANDC__
void _ffree(void _far *fp);
size_t _fmsize(void _far *memblock);
void _nfree(void _near *memblock);
size_t _nmsize(void _near *memblock);
#endif
#define MAKEP(seg,ofs) \
((void _far *)(((DWORD)(seg) << 16) | (unsigned) (ofs)))
#define SELECTOROF(fp) ((WORD)(((DWORD)(fp)) >> 16))
#define OFFSETOF(fp) ((WORD)(DWORD)(fp))
#define MAX_SEL 1024 /* enough for 64 megabytes */
typedef struct {
WORD sel;
WORD items;
WORD failsize;
} MEMHEAP;
static MEMHEAP _near *memheap = 0;
static int numheaps = 0;
/* for stats */
static unsigned long num_try_allocs = 0L;
static unsigned long num_bmallocs = 0L;
static unsigned long num_try_frees = 0L;
static unsigned long num_fmalloc = 0L;
static unsigned long num_frealloc = 0L;
static unsigned long num_ffree = 0L;
static unsigned long num_get_pheap_loops = 0L;
static MEMHEAP _near *add_heap(unsigned initial_size);
static BOOL memheap_init(void);
static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size);
static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs);
static MEMHEAP _near *get_pheap(unsigned sel);
static BOOL malloc_fail(unsigned size);
/**********************************************************************/
unsigned _near _cdecl _amblksiz = 4096;
void _far *_fmalloc(unsigned size)
{
void _far *ret;
static MEMHEAP _near *pheap = 0;
MEMHEAP _near *skip;
int i;
retry:
num_fmalloc++;
if (! memheap) /* one-time initialization */
if (! memheap_init())
{
if (malloc_fail(size))
return NULL;
else
goto retry;
}
/* special case for large (32k+) blocks */
if (size > (WORD) (32 << 10))
{
HANDLE h;
h = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT,
size);
if (h)
return GlobalLock(h);
else if (malloc_fail(size))
return NULL;
else
goto retry;
}
/* try most recently used pheap first: not surprisingly, this
dramatically improves performance */
if (! pheap) pheap = memheap;
if ((ret = try_alloc(pheap, size)) != NULL)
return ret;
else
skip = pheap; /* don't check this one again */
/* try to find a heap from which to allocate block */
for (i=numheaps, pheap=memheap; i--; pheap++)
if (pheap != skip) /* don't retry one we tried already */
if ((ret = try_alloc(pheap, size)) != NULL) /* first fit */
return ret;
/* still here: need to allocate a new heap and try once more */
if ((pheap = add_heap(max(size, _amblksiz))) != NULL)
if ((ret = try_alloc(pheap, size)) != NULL)
return ret;
/* still here: memory totally exhausted */
if (malloc_fail(size))
return NULL;
else
goto retry;
}
void _far *_fcalloc(unsigned num, unsigned size)
{
return _fmalloc(num * size);
}
void _far *_fexpand(void _far *memblock, size_t size)
{
NPSTR np;
WORD old_size;
WORD sel = SELECTOROF(memblock);
WORD ofs = OFFSETOF(memblock);
if (ofs == 0)
{
HANDLE h = GlobalHandle(sel);
if (GlobalReAlloc(h,
GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size) == NULL)
return NULL;
else
return memblock;
}
old_size = _bmsize(sel, ofs);
if (np = (NPSTR) _bexpand(sel, ofs, size))
{
MEMHEAP _near *pheap = get_pheap(sel);
return MAKEP(sel, np);
}
else
return NULL;
}
void _far *_frealloc(void _far *memblock, unsigned size)
{
void _far *fp;
num_frealloc++;
if (OFFSETOF(memblock) == 0)
{
HANDLE h = GlobalHandle(SELECTOROF(memblock));
GlobalUnlock(h);
if (GlobalReAlloc(h,
GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT, size) == NULL)
return NULL;
else
return GlobalLock(h);
}
/* first try to expand the block in place */
if ((fp = _fexpand(memblock, size)) != NULL)
return fp;
else if (fp = _fmalloc(size))
{
WORD old_size = _fmsize(memblock);
_fmemcpy(fp, memblock, min(old_size, size));
_ffree(memblock);
return fp;
}
else
return NULL;
}
void _ffree(void _far *fp)
{
WORD sel, ofs;
MEMHEAP _near *pheap;
num_ffree++;
if (fp == NULL)
return;
sel = SELECTOROF(fp);
ofs = OFFSETOF(fp);
/* special case for (large) global blocks */
if (ofs == 0)
{
HANDLE h = GlobalHandle(sel);
GlobalUnlock(h);
GlobalFree(h);
return;
}
if ((pheap = get_pheap(sel)) != NULL)
try_free(pheap, sel, ofs);
}
size_t _fmsize(void _far *memblock)
{
unsigned sel = SELECTOROF(memblock);
unsigned ofs = OFFSETOF(memblock);
return ofs? _bmsize(sel, ofs) : GlobalSize(GlobalHandle(sel));
}
/**********************************************************************/
static BOOL memheap_init(void)
{
HANDLE h;
h = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, MAX_SEL * sizeof(MEMHEAP));
if (h == NULL)
return FALSE;
if ((memheap = (MEMHEAP _near *) LocalLock(h)) == NULL)
return FALSE;
if (add_heap(_amblksiz) == NULL)
return FALSE;
return TRUE;
}
static MEMHEAP _near *get_pheap(unsigned sel)
{
static MEMHEAP _near *pheap = (MEMHEAP _near *) 0;
int i;
if (! pheap)
pheap = memheap;
if (pheap->sel == sel)
return pheap;
num_get_pheap_loops++;
for (i=numheaps, pheap=memheap; i--; pheap++)
if (pheap->sel == sel)
return pheap;
/* still here */
return NULL;
}
static MEMHEAP _near *add_heap(unsigned initial_size)
{
WORD sel;
MEMHEAP _near *pheap;
int i;
if ((sel = _bheapseg(initial_size)) == (WORD) -1)
return NULL;
/* find first free space in memheap array */
for (i=0, pheap=memheap; i<numheaps; i++, pheap++)
if (pheap->sel == 0)
break;
if (i==numheaps)
numheaps++;
pheap->sel = sel;
pheap->items = 0;
pheap->failsize = 0xFFFFU;
return pheap;
}
static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size)
{
NPSTR np;
num_try_allocs++;
if (pheap->sel && (pheap->failsize > size))
{
num_bmallocs++;
if ((np = (NPSTR) _bmalloc(pheap->sel, size)) != NULL)
{
pheap->items++;
return MAKEP(pheap->sel, np);
}
else
pheap->failsize = size;
}
return NULL;
}
static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs)
{
WORD size;
num_try_frees++;
if (pheap->sel != sel)
return FALSE;
size = _bmsize(sel, ofs);
_bfree(sel, (NPSTR) ofs);
pheap->failsize += size; // rough estimate okay
pheap->items--;
if (pheap->items == 0) // return empties to Windows
{
if (_bfreeseg(pheap->sel) == 0)
{
pheap->sel = 0;
return TRUE;
}
else
return FALSE;
}
return TRUE;
}
/**********************************************************************/
static BOOL (*malloc_fail_handler)(unsigned size) = 0;
void set_malloc_fail_handler(BOOL (*handler)(unsigned))
{
malloc_fail_handler = handler;
}
BOOL malloc_fail(unsigned size)
{
static in_fail_handler = 0;
if (malloc_fail_handler && (in_fail_handler == 0))
{
BOOL ret;
in_fail_handler++;
ret = (*malloc_fail_handler)(size);
in_fail_handler--;
return ret;
}
else
return TRUE; // fail, don't retry
}
/**********************************************************************/
winheap_stats()
{
MEMHEAP _near *pheap;
int i;
unsigned num_live_heaps=0;
for (i=numheaps, pheap=memheap; i--; pheap++)
if (pheap->sel) num_live_heaps++;
printf("Calls to _fmalloc: %lu\n", num_fmalloc);
printf("Calls to try_alloc: %lu\n", num_try_allocs);
printf("Calls to _bmalloc: %lu\n", num_bmallocs);
printf("Calls to _frealloc: %lu\n", num_frealloc);
printf("Calls to _ffree: %lu\n", num_ffree);
printf("Calls to try_free: %lu\n", num_try_frees);
printf("Get heap loops: %lu\n", num_get_pheap_loops);
printf("Heaps: %u\n", num_live_heaps);
printf("Freed heaps: %u\n", numheaps - num_live_heaps);
}
/**********************************************************************/
/* 0 as first argument to _bxxxx functions: use default data seg */
typedef void _near *NPTR;
NPTR _nmalloc(size_t size) { return _bmalloc(0, size); }
NPTR _ncalloc(unsigned num, unsigned size) { return _bcalloc(0, num, size); }
NPTR _nexpand(NPTR blk, size_t size) { return _bexpand(0, blk, size); }
NPTR _nrealloc(NPTR blk, size_t size) { return _brealloc(0, blk, size); }
void _nfree(NPTR memblock) { return _bfree(0, memblock); }
size_t _nmsize(NPTR memblock) { return _bmsize(0, memblock); }
/**********************************************************************/
#if defined(M_I86SM) || defined(M_I86MM)
/* small or medium model */
#define _FN(x) _n ## x
#else
/* large or compact model */
#define _FN(x) _f ## x
#endif
void *malloc(size_t size) { return _FN(malloc(size)); }
void *calloc(size_t num, size_t size) { return _FN(calloc(num, size)); }
void *realloc(void *blk, size_t size) { return _FN(realloc(blk, size)); }
void *_expand(void *blk, size_t size) { return _FN(expand(blk, size)); }
void free(void *blk) { return _FN(free(blk)); }
size_t _msize(void *blk) { return _FN(msize(blk)); }